package binaryTree;

import java.util.ArrayList;

/**
 * Created by anatolii.bondarenko on 2/3/14.
 */
public class Node {
    private Node left;
    private Node right;
    private String name;
    private boolean root;
    private Node parent;
    private int level;
    private static ArrayList<Node> nodes = new ArrayList<Node>(0);

    public Node(String n){
        name = n;
        level = 1;
        root = true;
        nodes.add(this);
    }

    private void setLevel(int l){
        level = l;
    }
    private int getLevel(){
        return level;
    }
    private Node getParent(){
        return parent;
    }

    private void setParent(Node n){
        parent = n;
    }

    private void setRoot(){
        root = true;
    }

    private void setLeft(Node n){
        left = n;
        if (n!=null){
            n.setParent(this);
            n.setLevel(n.getParent().getLevel()+1);
        }
    }

    private void setRight(Node n){
        right = n;
        if (n!=null){
            n.setParent(this);
            n.setLevel(n.getParent().getLevel()+1);
        }
    }

    private static void reduceLevel(Node n){
        n.setLevel(n.getLevel()-1);
        if (n.getLeft() != null && n.getRight()!=null){
            reduceLevel(n.getRight());
            reduceLevel(n.getLeft());
        }
        else if (n.getLeft()!=null){
            reduceLevel(n.getLeft());
        }
        else if (n.getRight()!=null){
            reduceLevel(n.getRight());
        }
    }
    public String getName(){
        return name;
    }

    public boolean isRoot(){
        return root;
    }

    public Node getLeft(){
        return left;
    }

    public Node getRight(){
        return right;
    }

    public void addLeft(Node n){
        if (left == null){
            setLeft(n);
        }
        else {
            Node buff;
            buff = this.getLeft();
            setLeft(n);
            n.setLeft(buff);
        }
    }

    public void addRight(Node n){
        if (right == null){
            setRight(n);
        }
        else {
            Node buff;
            buff = this.getRight();
            setRight(n);
            n.setRight(buff);
        }
    }

    public static void removeNode(Node n){
        if(n.getLeft()!=null && n.getRight()!=null){
            System.out.println("This node cannot be removed from tree");
        }
        else {
            //if node to remove is root
            if (n.getParent()==null && n.isRoot()){
                if (n.getLeft()!=null){
                    n.getLeft().setRoot();
                    n.getLeft().setParent(null);
                    reduceLevel(n.getLeft());
                    n.setLevel(1);
                }
                else if (n.getRight()!=null){
                    n.getRight().setRoot();
                    n.getRight().setParent(null);
                    reduceLevel(n.getRight());
                    n.setLevel(1);
                }
            }
            //if node to remove is left
            else if (n.getParent().getLeft()!=null && n.getParent().getLeft().equals(n)){
                if (n.getLeft()!=null){
                    reduceLevel(n.getLeft());
                    n.getParent().setLeft(n.getLeft());
                    n.setLevel(1);
                }
                else if (n.getRight()!=null){
                    reduceLevel(n.getRight());
                    n.getParent().setLeft(n.getRight());
                    n.setLevel(1);
                }
                else {
                    n.getParent().setLeft(null);
                    n.setLevel(1);
                }
            }
            //if node to remove is right
            else if (n.getParent().getRight().equals(n)){
                if (n.getLeft()!=null){
                    reduceLevel(n.getLeft());
                    n.getParent().setRight(n.getLeft());
                    n.setLevel(1);
                }
                else if (n.getRight()!=null){
                    reduceLevel(n.getRight());
                    n.getParent().setRight(n.getRight());
                    n.setLevel(1);
                }
                else {
                    n.getParent().setRight(null);
                    n.setLevel(1);
                }
            }
        }
    }

    public static int getHeightOfTheTree(){
        ArrayList<Integer> levels = new ArrayList<Integer>(nodes.size());
        for(int i = 0; i < nodes.size(); i++){
            levels.add(nodes.get(i).getLevel());
        }
        Integer max = levels.get(0);
        for(int i = 0; i < levels.size(); i++){
            if (max < levels.get(i)){
                max = levels.get(i);
            }
        }
        return max;
    }


}
